﻿using Avalonia.Threading;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using SD.App.Desktop.Entity;
using SD.App.Desktop.Model;
using SD.App.Desktop.Service;
using SD.App.Desktop.Utils;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Input;

namespace SD.App.Desktop.ViewModels
{
    public class RegisterViewModel : ReactiveObject, IDisposable, ITransientLifetime
    {
        // 表单字段
        [Reactive] 
        public string Username { get; set; } = string.Empty;
        [Reactive] 
        public string Password { get; set; } = string.Empty;
        [Reactive]
        public string ConfirmPassword { get; set; } = string.Empty;
        [Reactive]
        public string Email { get; set; } = string.Empty;

        // 错误信息
        [Reactive]
        public string UsernameError { get; set; } = string.Empty;
        [Reactive]
        public string PasswordError { get; set; } = string.Empty;
        [Reactive]
        public string ConfirmPasswordError { get; set; } = string.Empty;
        [Reactive]
        public string EmailError { get; set; } = string.Empty;

        [Reactive] 
        public bool IsLoading { get; set; } = false;
        [Reactive] 
        public string ErrorMessage { get; set; } = string.Empty;

        // 命令
        public ReactiveCommand<Unit, bool> RegisterCommand { get; }
        // 重置命令
        public ICommand ResetCommand { get; }
        // 跳转登录命令
        public ICommand GotoLoginCommand { get; }

        private readonly CompositeDisposable _disposables = new();

        private readonly ILogger _logger;
        private readonly IMessageService _messageService;
        private readonly IUserService _userService;

        public RegisterViewModel(ILogger logger,
            IMessageService messageService,
            IUserService userService)
        {
            _logger = logger;
            _messageService = messageService;
            _userService = userService;


            // 1. 用户名校验流：必填 + 长度（3-20位）
            var usernameValidate = this.WhenAnyValue(vm => vm.Username)
                .Skip(1) // 跳过初始值（空字符串）的校验触发
                .Select(username =>
                {
                    // 先校验必填，再校验长度（短路逻辑：必填失败则不进入长度校验）
                    var requiredError = ValidateRules.Required(username, "用户名");
                    if (!string.IsNullOrEmpty(requiredError))
                        return requiredError;

                    // 必填通过后，进入长度校验
                    return ValidateRules.Length(username, 3, 20, "用户名");
                });

            // 2. 密码校验流：必填 + 长度（6-16位）+ 强度
            var passwordValidate = this.WhenAnyValue(vm => vm.Password)
                .Skip(1) // 跳过初始值（空字符串）的校验触发
                .Select(password =>
                {
                    var requiredError = ValidateRules.Required(password, "密码");
                    if (!string.IsNullOrEmpty(requiredError))
                        return requiredError;

                    var lengthError = ValidateRules.Length(password, 6, 16, "密码");
                    if (!string.IsNullOrEmpty(lengthError))
                        return lengthError;

                    return ValidateRules.Password(password);
                });

            // 3. 确认密码校验流：必填 + 一致性
            var confirmPwdValidate = this.WhenAnyValue(vm => vm.Password, vm => vm.ConfirmPassword)
                .Skip(1) // 跳过初始值（空字符串）的校验触发
                .Select(t =>
                {
                    // 核心逻辑：仅在以下情况校验确认密码
                    // 情况1：确认密码已被用户编辑（输入过内容）
                    // 情况2：确认密码未编辑，但已输入内容（非空）
                    if (string.IsNullOrEmpty(t.Item2))
                    {
                        // 确认密码为空 → 不校验，返回空错误
                        return string.Empty;
                    }

                    var requiredError = ValidateRules.Required(t.Item2, "确认密码");
                    if (!string.IsNullOrEmpty(requiredError))
                        return requiredError;

                    var lengthError = ValidateRules.Length(t.Item2, 6, 16, "确认密码");
                    if (!string.IsNullOrEmpty(lengthError))
                        return lengthError;

                    return t.Item1 != t.Item2 ? "两次密码不一致" : string.Empty;
                });


            // 4. 邮箱校验流：格式（可选字段，空值不校验）
            var emailValidate = this.WhenAnyValue(vm => vm.Email)
                .Skip(1) // 跳过初始值（空字符串）的校验触发
                .Select(ValidateRules.Email);

            // 5. 绑定校验结果到错误字段（关键：确保校验流输出被接收）
            usernameValidate
                .BindTo(this, vm => vm.UsernameError)
                .DisposeWith(_disposables);

            passwordValidate
                .BindTo(this, vm => vm.PasswordError)
                .DisposeWith(_disposables);

            confirmPwdValidate
                .BindTo(this, vm => vm.ConfirmPasswordError)
                .DisposeWith(_disposables);

            emailValidate
                .BindTo(this, vm => vm.EmailError)
                .DisposeWith(_disposables);

            // 6. 提交按钮状态：所有错误字段为空
            var canRegister = this.WhenAnyValue(
                vm => vm.Username,
                vm => vm.Password,
                vm => vm.ConfirmPassword,
                vm => vm.UsernameError,
                vm => vm.PasswordError,
                vm => vm.ConfirmPasswordError,
                vm => vm.EmailError,
                vm => vm.IsLoading,
                (name, password, confirmPassword, u, p, cp, e, isLoading) => !string.IsNullOrEmpty(name) 
                    && !string.IsNullOrEmpty(Password)
                    && !string.IsNullOrEmpty(ConfirmPassword)
                    && string.IsNullOrEmpty(u) 
                    && string.IsNullOrEmpty(p) 
                    && string.IsNullOrEmpty(cp) 
                    && string.IsNullOrEmpty(e)
                    && !isLoading);

            // 7. 命令实现
            RegisterCommand = ReactiveCommand.CreateFromTask(ExecuteRegisterAsync, canRegister)
                .DisposeWith(_disposables);

            // 重置命令
            ResetCommand = ReactiveCommand.Create(ResetRegisterForm)
                 .DisposeWith(_disposables);

            // 跳转登录命令（仅作为触发，逻辑由 UI 层实现）
            GotoLoginCommand = ReactiveCommand.Create(() => { })
                .DisposeWith(_disposables);

        }

        public void Dispose() => _disposables.Dispose();

        /// <summary>
        /// 执行注册逻辑
        /// </summary>
        private async Task<bool> ExecuteRegisterAsync()
        {
            IsLoading = true;
            ErrorMessage = string.Empty;
            try
            {
                // 构建注册 DTO
                var registerDto = new RegisterDto
                {
                    Username = Username,
                    Password = Password,
                    ConfirmPassword = ConfirmPassword,
                    Email = Email,
                    // Phone = string.IsNullOrWhiteSpace(Phone) ? null : Phone
                };

                // 调用 Service 注册方法
                User? newUser = await _userService.RegisterAsync(registerDto);
                return newUser != null;
            }
            catch (InvalidOperationException ex)
            {
                // 业务异常（参数错误、用户名已存在等）
                ErrorMessage = ex.Message;
                _logger.Warning("注册失败：{ErrorMessage}", ex.Message);
                return false;
            }
            catch (Exception ex)
            {
                // 系统异常
                ErrorMessage = "注册失败，请联系管理员";
                _logger.Error(ex, "注册异常");
                _messageService.ShowError("注册异常：" + ex.Message);
                return false;
            }
            finally
            {
                IsLoading = false;
            }
        }

        /// <summary>
        /// 重置注册表单
        /// </summary>
        private void ResetRegisterForm()
        {
            Username = string.Empty;
            Password = string.Empty;
            ConfirmPassword = string.Empty;
            Email = string.Empty;
            ErrorMessage = string.Empty;
            _logger.Debug("注册表单已重置");
        }
    }
}
